<?php

/**
 * This function tries to load the include files as needed. If the file
 * isn't found returns false which will result in throwing an exception,
 * otherwise it will return true signalling the function succeded and the
 * file was included.
 *
 * @param String $className
 * @return boolean
 */
function autoloadClasses($className) {
    $classPath = __DIR__ . '/Code/' . $className . '.php';
    if (file_exists($classPath)) {
        // include the class file
        include $classPath;
        return true;
    } else {
        // it's important to return false so that the interpreter can throw
        // a class not found fatal error
        // or to move to the next autoload function
        return false;
    }
}

// register the above function
spl_autoload_register("autoloadClasses");

class APIObject{

    // Field variables
    public $secureUrl = "http://book.api.ean.com/ean-services/rs/hotel/v3/";
    public $unsecureUrl = "http://api.ean.com/ean-services/rs/hotel/v3/";
    public $baseRequest = null;

    /**
     * Generates the md5 hash code which is used for authentification
     * @param string $apiKey - Application hash code
     * @param string $sharedSecret - The secret code used for md5 generator
     * @return string - Returns a md5 Hash
     */
    public function GetSignature($apiKey, $sharedSecret) {
        $timestamp = gmdate('U'); // 1200603038
        return md5($apiKey . $sharedSecret . $timestamp);
    }

    /**
     * EAN API Code for mananging the php objects. It can:
     *      > create requests
     *      > parse responses
     * using REST paradigms.
     *
     * @param string $apiKey - Application hash code
     * @param string $sharedSecret - The secret code used for md5 generator
     * @param integer $cid - The Client ID
     * @param integer $minorRevision - The development minor version
     * @param string $locale - The language in which data should be returned.
     * @param string $currencyCode - Currency Code USD, EUR etc.
     * @param integer $mode - AUTH Method: 1 - Signature AUTH; 2 - IP PRO AUTH
     */
    public function __construct($apiKey = "cbrzfta369qwyrm9t5b8y8kf", $sharedSecret = "", $cid = 55505, $minorRevision = 16, $locale = "en_EN", $currencyCode = "USD", $mode = 2) {
        // Get Client IP Address and UserAgent
        $userAgent = $_SERVER['HTTP_USER_AGENT'];
        $userIpAddress = $this->GetIpAddress(); //$_SERVER['REMOTE_ADDR'];
        // Create a BaseRequest and send all the data
        $this->baseRequest = new BaseRequest();
        $this->baseRequest->apiKey = $apiKey;
        $this->baseRequest->cid = $cid;
        $this->baseRequest->currencyCode = $currencyCode;
        $this->baseRequest->customerIpAddress = ($userIpAddress == "::1") ? "127.0.0.1" : $userIpAddress;
        $this->baseRequest->customerSessionId = "";
        $this->baseRequest->customerUserAgent = urlencode($userAgent);
        $this->baseRequest->minorRev = $minorRevision;
        $this->baseRequest->debug = TRUE;
        $this->baseRequest->locale = $locale;
        $this->baseRequest->test = TRUE;
        if ($mode === 1) // Uses signature AUTH
            $this->baseRequest->sig = $this->GetSignature($apiKey, $sharedSecret);
        else { // Uses IP PRO AUTH
            $this->baseRequest->sig = "";
        }
    }

    /**
     * Gets the client's IP Address
     * @return string Return IP Address
     */
    public function GetIpAddress() {
        foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR',
    'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP',
    'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
            if (array_key_exists($key, $_SERVER) === true) {
                foreach (explode(',', $_SERVER[$key]) as $ip) {
                    if (filter_var($ip, FILTER_VALIDATE_IP) !== false) {
                        return $ip;
                    }
                }
            }
        }
    }

    /**
     * Prints on the screen the object with the member data.
     * @param mixed $data
     * @param string $text
     */
    public function PrintTestDataOnScreen($data, $text) {
        echo "Begin Test Data Print <br />";
        echo $text . PHP_EOL;
        echo PHP_EOL;
        echo "<pre>";
        print_r($data);
        echo "</pre>";
        echo "End Test Data Print <br />";
    }

    /**
     * Checks to see if the server is available
     * @param string $echoText
     * @return boolean
     */
    public function PingServer($echoText) {
        if ($this->isValidVariables(array($echoText))) {
            // Create a ping request
            $pingReq = new PingRequest($echoText);
            $pingReq->InheritPropertiesFrom($this->baseRequest);

            // Call the API, and get the response
            $pingRes = $this->Call($pingReq);
            //$this->PrintTestDataOnScreen($pingRes, "hERE");
            // Check if the returned echo is the same as the one we sent
            if ($pingRes->echo === $echoText) {
                // if succeeded return the data
                return $pingRes->ServerInfo;
            } else {
                return FALSE; // The request failed
            }
        }
        return FALSE; // The function failed
    }

    /**
     * Checks if the variable are empty or not.
     * @param array $vars
     * @return boolean
     * @todo Need to check against class params
     */
    private function isValidVariables($vars) {
        //print_r($vars);
        if (!is_array($vars)) {
            return false;
        } else {
            foreach ($vars as $var) {
                if (empty($var)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Gets the API response for a certain request
     *
     * @param mixed $object - The request
     * @param string $mode - The mode to use, to get data from a secure link(used for bookings)
     * @return mixed - Returns the new object created from the json response.
     */
    private function Call($object, $mode = "UNSECURE") {
        $returnObjectName = "";
        $serviceName = "";
        $url = "";

        if ($mode == "UNSECURE") {
            $url = $this->unsecureUrl;
        } elseif ($mode == "SECURE") {
            $url = $this->secureUrl;
        } else {
            return FALSE;
        }

        switch (get_class($object)) {
            case "PingRequest":
                $serviceName = "ping?";
                $returnObjectName = "PingResponse";
                break;
            case "HotelListRequest":
                $serviceName = "list?";
                $returnObjectName = "HotelListResponse";
                break;
            case "HotelRoomAvailabilityRequest":
                $serviceName = "avail?";
                $returnObjectName = "HotelRoomAvailabilityResponse";
                break;
            case "HotelInformationRequest":
                $serviceName = "info?";
                $returnObjectName = "HotelInformationResponse";
                break;
            case "HotelItineraryRequest":
                $serviceName = "itin?";
                $returnObjectName = "HotelItineraryResponse";
                break;
            default:
                break;
        }
        $url = $this->unsecureUrl . $serviceName . http_build_query($object);

        // initialize curl
        $ch = curl_init();

        // Set CURL Headers
        $header[] = "Accept: application/json";
        $header[] = "Accept-Encoding: gzip";

        // Set CURL Options
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_ENCODING, "gzip");
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // Execute CURL Data and get a decodified JSON Object
        $jsonObject = json_decode(curl_exec($ch));

        $response = $this->CreateObject($returnObjectName, $jsonObject->$returnObjectName);

        // $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        // Close & Release CURL
        curl_close($ch);

        return $response;
    }

    /**
     * Creates from a json object a new object which is the response to a
     * specific request
     *
     * @param string $name - type of the object to be created
     * @param mixed $object - json object to be parsed
     * @return name
     */
    private function CreateObject($name, $object) {
        if ($name != null) {
            if ($name === "RateInfo") {
                $newObj = new HotelRateInfo();
            } else {
                $newObj = new $name;
            }
        }
        $list = get_object_vars($object);
        foreach ($list as $key => $value) {
            if (gettype($value) === "object") {
                $newObj->$key = $this->CreateObject($key, $value);
            } else {
                if (gettype($value) !== NULL) {
                    $newObj->$key = $value;
                }
            }
        }
        return $newObj;
    }

    /**
     * Gets a list with the available hotels.
     * @param string $arrivalDate
     * @param string $departureDate
     * @param int $numberOfResults
     * @param string $city
     * @param string $stateProvinceCode
     * @param string $countryCode
     * @param Filter $filters
     * @param string $options
     * @param string $optimization
     * @return mixed
     */
    public function GetHotelList_City($arrivalDate, $departureDate, $numberOfResults, $city, $stateProvinceCode, $countryCode, $filters, $options, $optimization) {
        $roomargs = $filters->getRoomGroupRest();
        $args = array(
            "arrivalDate" => $arrivalDate,
            "departureDate" => $departureDate,
            "numberOfResults" => $numberOfResults,
            "city" => $city,
            "stateProvinceCode" => $stateProvinceCode,
            "countryCode" => $countryCode,
            "address" => $filters->address,
            "postalCode" => $filters->postalCode,
            "propertyName" => $filters->propertyName,
            "propertyCategory" => $filters->propertyCategory,
            "amenities" => $filters->amenities,
            "maxStarRating" => $filters->maxStarRating,
            "minStarRating" => $filters->minStarRating,
            "minRate" => $filters->minRate,
            "maxRate" => $filters->maxRate,
            "supplierType" => $filters->supplierType,
            "numberOfBedRooms" => $filters->numberOfBedRooms,
            "sort" => $filters->sort,
            "maxRatePlanCount" => $filters->maxRatePlanCount,
            "options" => $options,
            "optimization" => $optimization
        );
        foreach ($roomargs as $key => $value) {
            $args[$key] = $value;
        }
        $args["_type"] = "json";

        $hotelsReq = new HotelListRequest($args);
        $hotelsReq->InheritPropertiesFrom($this->baseRequest);
        // Call the API, and get the response
        $hotelsRes = $this->Call($hotelsReq);

        return $hotelsRes;
    }

    /**
     * Gets a list of hotels by specifying a destination.
     * @param string $arrivalDate
     * @param string $departureDate
     * @param int $numberOfResults
     * @param string $destinationString
     * @param Filter $filters
     * @param string $options
     * @param string $optimization
     * @return mixed
     */
    public function GetHotelList_DestinationString($arrivalDate, $departureDate, $numberOfResults, $destinationString, $filters, $options, $optimization) {
        $roomargs = $filters->getRoomGroupRest();
        $args = array(
            "arrivalDate" => $arrivalDate,
            "departureDate" => $departureDate,
            "numberOfResults" => $numberOfResults,
            "destinationString" => $destinationString,
            "address" => $filters->address,
            "postalCode" => $filters->postalCode,
            "propertyName" => $filters->propertyName,
            "propertyCategory" => $filters->propertyCategory,
            "amenities" => $filters->amenities,
            "maxStarRating" => $filters->maxStarRating,
            "minStarRating" => $filters->minStarRating,
            "minRate" => $filters->minRate,
            "maxRate" => $filters->maxRate,
            "supplierType" => $filters->supplierType,
            "numberOfBedRooms" => $filters->numberOfBedRooms,
            "sort" => $filters->sort,
            "maxRatePlanCount" => $filters->maxRatePlanCount,
            "options" => $options,
            "optimization" => $optimization
        );

        foreach ($roomargs as $key => $value) {
            $args[$key] = $value;
        }
        $args["_type"] = "json";

        $hotelsReq = new HotelListRequest($args);
        $hotelsReq->InheritPropertiesFrom($this->baseRequest);

        // Call the API, and get the response
        $hotelsRes = $this->Call($hotelsReq);

        return $hotelsRes;
    }

    /**
     * Gets a list of hotels by specying the destination id.
     * @param string $arrivalDate
     * @param string $departureDate
     * @param int $numberOfResults
     * @param id $destinationId
     * @param Filter $filters
     * @param string $options
     * @param string $optimization
     * @return mixed
     */
    public function GetHotelList_DestinationId($arrivalDate, $departureDate, $numberOfResults, $destinationId, $filters, $options, $optimization) {
        $roomargs = $filters->getRoomGroupRest();
        $args = array(
            "arrivalDate" => $arrivalDate,
            "departureDate" => $departureDate,
            "numberOfResults" => $numberOfResults,
            "destinationId" => $destinationId,
            "address" => $filters->address,
            "postalCode" => $filters->postalCode,
            "propertyName" => $filters->propertyName,
            "propertyCategory" => $filters->propertyCategory,
            "amenities" => $filters->amenities,
            "maxStarRating" => $filters->maxStarRating,
            "minStarRating" => $filters->minStarRating,
            "minRate" => $filters->minRate,
            "maxRate" => $filters->maxRate,
            "supplierType" => $filters->supplierType,
            "numberOfBedRooms" => $filters->numberOfBedRooms,
            "sort" => $filters->sort,
            "maxRatePlanCount" => $filters->maxRatePlanCount,
            "options" => $options,
            "optimization" => $optimization
        );

        foreach ($roomargs as $key => $value) {
            $args[$key] = $value;
        }
        $args["_type"] = "json";

        $hotelsReq = new HotelListRequest($args);
        $hotelsReq->InheritPropertiesFrom($this->baseRequest);

        // Call the API, and get the response
        $hotelsRes = $this->Call($hotelsReq);

        return $hotelsRes;
    }

    /**
     * Gets all the available hotels from the hotelList.
     * @param string $arrivalDate
     * @param string $departureDate
     * @param int $numberOfResults
     * @param int[] $hotelIdList
     * @param Filter $filters
     * @param string $options
     * @param string $optimization
     * @return mixed
     */
    public function GetHotelList_HotelIdList($arrivalDate, $departureDate, $numberOfResults, $hotelIdList, $filters, $options, $optimization) {
        $roomargs = $filters->getRoomGroupRest();
        $args = array(
            "arrivalDate" => $arrivalDate,
            "departureDate" => $departureDate,
            "numberOfResults" => $numberOfResults,
            "hotelIdList" => $hotelIdList,
            "address" => $filters->address,
            "postalCode" => $filters->postalCode,
            "propertyName" => $filters->propertyName,
            "propertyCategory" => $filters->propertyCategory,
            "amenities" => $filters->amenities,
            "maxStarRating" => $filters->maxStarRating,
            "minStarRating" => $filters->minStarRating,
            "minRate" => $filters->minRate,
            "maxRate" => $filters->maxRate,
            "supplierType" => $filters->supplierType,
            "numberOfBedRooms" => $filters->numberOfBedRooms,
            "sort" => $filters->sort,
            "maxRatePlanCount" => $filters->maxRatePlanCount,
            "options" => $options,
            "optimization" => $optimization
        );

        foreach ($roomargs as $key => $value) {
            $args[$key] = $value;
        }
        $args["_type"] = "json";

        $hotelsReq = new HotelListRequest($args);
        $hotelsReq->InheritPropertiesFrom($this->baseRequest);

        // Call the API, and get the response
        $hotelsRes = $this->Call($hotelsReq);

        return $hotelsRes;
    }

    /**
     * Gets a list of hotels use geographic coordonates.
     * @param string $arrivalDate
     * @param string $departureDate
     * @param int $numberOfResults
     * @param float $latitude
     * @param float $longitude
     * @param float $searchRadius
     * @param float $searchRadiusUnit
     * @param Filter $filters
     * @param string $options
     * @param string $optimization
     * @return mixed
     */
    public function GetHotelList_GeoSearch($arrivalDate, $departureDate, $numberOfResults, $latitude, $longitude, $searchRadius, $searchRadiusUnit, $filters, $options, $optimization) {
        $roomargs = $filters->getRoomGroupRest();
        $args = array(
            "arrivalDate" => $arrivalDate,
            "departureDate" => $departureDate,
            "numberOfResults" => $numberOfResults,
            "latitude" => $latitude,
            "longitude" => $longitude,
            "searchRadius" => $searchRadius,
            "searchRadiusUnit" => $searchRadiusUnit,
            "address" => $filters->address,
            "postalCode" => $filters->postalCode,
            "propertyName" => $filters->propertyName,
            "propertyCategory" => $filters->propertyCategory,
            "amenities" => $filters->amenities,
            "maxStarRating" => $filters->maxStarRating,
            "minStarRating" => $filters->minStarRating,
            "minRate" => $filters->minRate,
            "maxRate" => $filters->maxRate,
            "supplierType" => $filters->supplierType,
            "numberOfBedRooms" => $filters->numberOfBedRooms,
            "sort" => $filters->sort,
            "maxRatePlanCount" => $filters->maxRatePlanCount,
            "options" => $options,
            "optimization" => $optimization
        );

        foreach ($roomargs as $key => $value) {
            $args[$key] = $value;
        }
        $args["_type"] = "json";

        $hotelsReq = new HotelListRequest($args);
        $hotelsReq->InheritPropertiesFrom($this->baseRequest);

        // Call the API, and get the response
        $hotelsRes = $this->Call($hotelsReq);

        return $hotelsRes;
    }

    /**
     * Used for pagination. Continues getting hotel from the previous request.
     * @param string $cacheLocation
     * @param string $cacheKey
     * @return mixed
     */
    public function GetMoreHotels($cacheLocation, $cacheKey) {
        $args = array(
            "cacheLocation" => $cacheLocation,
            "cacheKey" => $cacheKey,
        );
        $hotelsReq = new HotelListRequest($args);
        $hotelsReq->InheritPropertiesFrom($this->baseRequest);

        // Call the API, and get the response
        $hotelsRes = $this->Call($hotelsReq);

        return $hotelsRes;
    }

    /**
     * Gets all the available information for a certain hotel.
     * @param int $hotelId
     * @param string $options
     * @return mixed
     */
    public function GetHotelInformation($hotelId, $options) {
        $args = array(
            "hotelId" => $hotelId,
            "options" => $options,
        );
        $hotelsInfoReq = new HotelInformationRequest($args);
        $hotelsInfoReq->InheritPropertiesFrom($this->baseRequest);

        // Call the API, and get the response

        $hotelsInfoRes = $this->Call($hotelsInfoReq);

        return $hotelsInfoRes;
    }

    /**
     * Gets the room availability for a certain hotel
     * @param int $hotelId
     * @param string $arrivalDate
     * @param string $departureDate
     * @param int $numberOfBedRooms
     * @param string $supplierType
     * @param string $rateKey
     * @param string $rateCode
     * @param string $roomTypeCode
     * @param boolean $includeDetails
     * @param boolean $includeRoomImages
     * @param string $options
     * @param RoomGroup $roomGroup
     * @return mixed
     */
    public function GetRoomAvailability($hotelId, $arrivalDate, $departureDate, $numberOfBedRooms, $supplierType, $rateKey, $rateCode, $roomTypeCode, $includeDetails, $includeRoomImages, $options, $roomGroup) {
        $roomargs = $roomGroup->getRoomGroupRest();
        $args = array(
            "hotelId" => $hotelId,
            "arrivalDate" => $arrivalDate,
            "departureDate" => $departureDate,
            "numberOfBedRooms" => $numberOfBedRooms,
            "supplierType" => $supplierType,
            "rateKey" => $rateKey,
            "rateCode" => $rateCode,
            "roomTypeCode" => $roomTypeCode,
            "postalCode" => $includeDetails,
            "options" => $options,
            "includeRoomImages" => $includeRoomImages
        );

        foreach ($roomargs as $key => $value) {
            $args[$key] = $value;
        }
        $args["_type"] = "json";

        $availReq = new HotelRoomAvailabilityRequest($args);
        $availReq->InheritPropertiesFrom($this->baseRequest);

        //$this->PrintTestDataOnScreen($availReq, "Avail Text");
        // Call the API, and get the response
        $availRes = $this->Call($availReq);

        return $availRes;
    }

    /**
     * Gets the itinerary data
     * @param type $itineraryId
     * @param type $email
     * @return \HotelItineraryRequest
     */
    public function GetItinerary($itineraryId, $email){
        $args = array(
            "itineraryId" => $itineraryId,
            "email" => $email,
            "_type" => "json"
        );
        $itinReq = new HotelItineraryRequest($args);
        $itinReq->InheritPropertiesFrom($this->baseRequest);

        $itinRes = $this->Call($itinReq);

        return $itinRes;
    }

}

?>